﻿/*! \file String.h

  \brief Строковые функции, алгоритмы , типы. <br>
 	Мягкая обёртка вокруг boost/algorithm/string.hpp с возможностью реализации собственных
  	алгоритмов без подключения библиотеки Boost

	<br>
	<br>

 *	\author Дмитрий Литовченко kvakvs@yandex.ru
 *	   && ksacvet777
 */


#pragma once
#define __KSSTR_H__
 

#include <iostream>
#include <cstdlib>
#include <cstdio>

#include <stdio.h>
#include <stdlib.h>

 
//#include <ostream>
//#include <iostream>
#include <assert.h>


#include <string>
#include <cctype>
#include <vector>
#include <list>
#include <set>

#include <cstring>
#include <string>
#include <cstdio>

//#include <gb/Config.h>
//#include <gb/base/Types.h>

 
#ifdef WIN32
	#include <windows.h> 
#endif
 

#pragma warning(push)
#pragma warning( disable : 4290 )


//! \brief Операции со строками , символами.
namespace ksstr
{
 	
//-------------------------------------------------------------------------
 
#ifdef WIN32

//! \brief Конвертация строк с помощью WinAPI
std::string convertWstringToAstringWinapi(const std::wstring& src  ) 	 throw (std::runtime_error);
//! \brief Конвертация строк с помощью WinAPI
std::wstring convertAstringToWstringWinapi(const std::string& src ) 	 throw (std::runtime_error);

#endif // win32

//! \brief  Тримировать строки
void trimStrings(std::vector<std::string>& a);


 
#ifdef WIN32

/** \brief Конвертирует исходную строку WCHAR (szwSrc) в строку CHAR (szBuff). 
  В destlen парадать размер приёмного буфера (szBuff) */
inline void CharFromWchar(char* szBuff, int destlen,  const WCHAR* szwSrc  ) 
{
	WideCharToMultiByte( CP_ACP, 0, 
		szwSrc, -1, szBuff, destlen, NULL, NULL );
}

/**  \brief Конвертирует исходную строку CHAR (szSrc) в строку WCHAR (szwBuff). 
 В destlen парадать размер приёмного буфера (szwBuff) */
inline void WcharFromChar(WCHAR* szwBuff,   int destlen, const char* szSrc ) 
{
    int ret =	MultiByteToWideChar( CP_ACP, 0, 
		szSrc, (int)strlen(szSrc)+1, szwBuff,  destlen );
}

#endif // win32


//-------------------------------------------------------------------------
		
std::string toUtf8( const std::wstring & wide_str );
std::wstring toWide( const std::string & utf8_str );

//! \brief Раскодирует один Unicode символ из потока байтов UTF8
//! \returns возвращает его длину в результате функции и код в out_result
unsigned int decodeUtf8Character( unsigned int & out_result, const char * utf8 );

unsigned int uint32FromHex (const std::string & s);
unsigned long long uint64FromHex (const std::string & s);



// Boost запрещён, стоянка велосипедов открывается здесь
#if ! KSSTR_ALLOW_BOOST_LIBRARY

//! \brief  Привести к верхнему регистру на месте
void toUpper( std::string & v );

//! \brief  Вернуть копию, приведённую к верхнему регистру
std::string toUpperCopy( const std::string & v );

//! \brief  Привести к нижнему регистру на месте
void toLower( std::string & v );

//! \brief  Вернуть копию, приведённую к нижнему регистру
std::string toLowerCopy( const std::string & v );

//! \brief  Обрезать пробелы и табуляции слева, на месте
void trimLeft( std::string & v );

//! \brief  Обрезать пробелы и табуляции слева, вернуть исправленную копию
std::string trimLeftCopy( const std::string & v );

//! \brief  Обрезать пробелы и табуляции справа, на месте
void trimRight( std::string & v );

//! \brief  Обрезать пробелы и табуляции справа, вернуть исправленную копию
std::string trimRightCopy( const std::string & v );

//! \brief  Обрезать пробелы и табуляции слева и справа, на месте
void trim( std::string & v );

//! \brief  Обрезать пробелы и табуляции слева и справа, вернуть исправленную копию
std::string trimCopy( const std::string & v );

//-------------------------------------------------------------------------
// Предикаты для использования в функциях поиска, или в обычных условиях
//-------------------------------------------------------------------------

//! \brief  Начинается ли строка text с фрагмента search?
bool startsWith( const std::string & text, const std::string & search );

//! \brief  Начинается ли строка text с фрагмента search? (без учёта регистра)
bool iStartsWith( const std::string & text, const std::string & search );

//! \brief  Завершается ли строка text фрагментом search?
bool endsWith( const std::string & text, const std::string & search );

//! \brief  Завершается ли строка text фрагментом search? (без учёта регистра)
bool iEndsWith( const std::string & text, const std::string & search );

//! Содержит ли строка text фрагмент search?
bool contains( const std::string & text, const std::string & search );
//! \brief  Содержит ли строка text фрагмент search? (без учёта регистра)
bool iContains( const std::string & text, const std::string & search );

//! \brief  Равны ли строки друг другу
//! (не имеет смысла в простом условии, но полезно, как предикат для поиска)
inline bool equals( const std::string & a, const std::string & b ) 
{
	return a == b;
}
//! \brief  Равны ли строки друг другу без учёта регистра?
//! (не имеет смысла в простом условии, но полезно, как предикат для поиска)
bool iEquals( const std::string & a, const std::string & b );

//
//
//

/** \brief  Разбить строку value на слова по символам указанным в split_charset, результат
 сложить в destination  */
void split( std::vector <std::string> & destination, const std::string & value, const std::string & split_charset );
void split( std::list <std::string> & destination, const std::string & value, const std::string & split_charset );
void split( std::set <std::string> & destination, const std::string & value, const std::string & split_charset );

//! \brief  Заменить первое вхождение search в строку input новым текстом replace
void replaceFirst( std::string & input, const std::string & search, const std::string & replace );

//! \brief  Заменить первое вхождение search в строку input новым текстом replace, вернуть исправленную копию
std::string replaceFirstCopy( const std::string & input, const std::string & search, const std::string & replace );

//!  \brief Заменить первое вхождение search в строку input новым текстом replace, без учёта регистра
void iReplaceFirst( std::string & input, const std::string & search, const std::string & replace );

//!  \brief Заменить первое вхождение search в строку input новым текстом replace, без учёта регистра, вернуть исправленную копию
std::string iReplaceFirstCopy( const std::string & input, const std::string & search, const std::string & replace );
		
//!  \brief Удалить первое вхождение search в строку input
void eraseFirst( std::string & input, const std::string & search );

//!  \brief Удалить первое вхождение search в строку input, вернуть исправленную копию
std::string eraseFirstCopy( const std::string & input, const std::string & search );

//!  \brief Удалить первое вхождение search в строку input, без учёта регистра
void iEraseFirst( std::string & input, const std::string & search );

//!  \brief Удалить первое вхождение search в строку input, без учёта регистра, вернуть исправленную копию
std::string iEraseFirstCopy( const std::string & input, const std::string & search );

//!  \brief Заменить последнее вхождение search в строку input новым текстом replace
void replaceLast( std::string & input, const std::string & search, const std::string & replace );

//!  \brief Заменить последнее вхождение search в строку input новым текстом replace, вернуть исправленную копию
std::string replaceLastCopy( const std::string & input, const std::string & search, const std::string & replace );

//!  \brief Заменить последнее вхождение search в строку input новым текстом replace, без учёта регистра
void iReplaceLast( std::string & input, const std::string & search, const std::string & replace );

//!  \brief Заменить последнее вхождение search в строку input новым текстом replace, без учёта регистра, вернуть исправленную копию
std::string iReplaceLastCopy( const std::string & input, const std::string & search, const std::string & replace );

//!  \brief Удалить последнее вхождение search в строку input
void eraseLast( std::string & input, const std::string & search );

//!  \brief Удалить последнее вхождение search в строку input, вернуть исправленную копию
std::string eraseLastCopy( const std::string & input, const std::string & search );

//!  \brief Удалить последнее вхождение search в строку input, без учёта регистра
void iEraseLast( std::string & input, const std::string & search );

//!  \brief Удалить последнее вхождение search в строку input, без учёта регистра, вернуть исправленную копию
std::string iEraseLastCopy( const std::string & input, const std::string & search );

/**  \brief Заменить N-е вхождение search в строку input новым текстом replace
    Отсчёт с нуля. Отрицательные N считаются с конца строки   */
void replaceNth( std::string & input, const std::string & search, int n, const std::string & replace );

/**  \brief  Заменить N-e вхождение search в строку input новым текстом replace, вернуть исправленную копию
   Отсчёт с нуля. Отрицательные N считаются с конца строки	*/
std::string replaceNthCopy( const std::string & input, const std::string & search, int n, const std::string & replace );

   /**  \brief  Заменить N-e вхождение search в строку input новым текстом replace, без учёта регистра
     Отсчёт с нуля. Отрицательные N считаются с конца строки  */
void iReplaceNth( std::string & input, const std::string & search, int n, const std::string & replace );
/**  \brief  Заменить N-e вхождение search в строку input новым текстом replace, без учёта регистра, вернуть исправленную копию
    Отсчёт с нуля. Отрицательные N считаются с конца строки  */
std::string iReplaceNthCopy( const std::string & input, const std::string & search, int n, const std::string & replace );

/**  \brief  Удалить N-e вхождение search в строку input
     Отсчёт с нуля. Отрицательные N считаются с конца строки */
void eraseNth( std::string & input, const std::string & search, int n );

/**  \brief  Удалить N-e вхождение search в строку input, вернуть исправленную копию
       Отсчёт с нуля. Отрицательные N считаются с конца строки */
std::string eraseNthCopy( const  std::string & input, const std::string & search, int n );

/**  \brief  Удалить N-e вхождение search в строку input, без учёта регистра
     Отсчёт с нуля. Отрицательные N считаются с конца строки  */
void iEraseNth( std::string & input, const std::string & search, int n );

/**  \brief  Удалить N-e вхождение search в строку input, без учёта регистра, вернуть исправленную копию
    Отсчёт с нуля. Отрицательные N считаются с конца строки  */
std::string iEraseNthCopy( const std::string & input, const std::string & search, int n );

//!  \brief  Заменить каждое вхождение search в строку input новым текстом replace
void replaceAll( std::string & input, const std::string & search, const std::string & replace );

//!  \brief Заменить каждое вхождение search в строку input новым текстом replace, вернуть исправленную копию
std::string replaceAllCopy( const std::string & input, const std::string & search, const std::string & replace );

//!  \brief Заменить каждое вхождение search в строку input новым текстом replace, без учёта регистра
void iReplaceAll( std::string & input, const std::string & search, const std::string & replace );

//!  \brief Заменить каждое вхождение search в строку input новым текстом replace, без учёта регистра, вернуть исправленную копию
std::string iReplaceAllCopy( const std::string & input, const std::string & search, const std::string & replace );

//!  \brief Удалить каждое вхождение search в строку input
void eraseAll( std::string & input, const std::string & search );

//!  \brief Удалить каждое вхождение search в строку input, вернуть исправленную копию
std::string eraseAllCopy( const std::string & input, const std::string & search );

//!  \brief Удалить каждое вхождение search в строку input, без учёта регистра
void iEraseAll( std::string & input, const std::string & search );

//!  \brief Удалить каждое вхождение search в строку input, без учёта регистра, вернуть исправленную копию
std::string iEraseAllCopy( const std::string & input, const std::string & search );

/**  \brief Заменить первые N символов строки input новым текстом replace
    Отсчёт с нуля. Для отрицательных N длина считается как (input.length() - abs(N)) */
void replaceHead( std::string & input, int n, const std::string & replace );

/**  \brief  Заменить первые N символов строки input новым текстом replace, вернуть исправленную копию
 Отсчёт с нуля. Для отрицательных N длина считается как (input.length() - abs(N)) */
std::string replaceHeadCopy( const std::string & input, int n, const std::string & replace );

/**  \brief  Заменить последние N символов строки input новым текстом replace
   Отсчёт с нуля. Для отрицательных N длина считается как (input.length() - abs(N)) */
void replaceTail( std::string & input, int n, const std::string & replace );

/**  \brief  Заменить последние N символов строки input новым текстом replace, вернуть исправленную копию
 Отсчёт с нуля. Для отрицательных N длина считается как (input.length() - abs(N)) */
std::string replaceTailCopy( const std::string & input, int n, const std::string & replace );
		
/**  \brief  Удалить первые N символов строки
  Отсчёт с нуля. Для отрицательных N длина считается как (input.length() - abs(N))*/
void eraseHead( std::string & input, int n );

/** \brief  Удалить первые N символов строки, вернуть исправленную копию
  Отсчёт с нуля. Для отрицательных N длина считается как (input.length() - abs(N))*/
std::string eraseHeadCopy( const std::string & input, int n );

/**  \brief  Удалить последние N символов строки
 Отсчёт с нуля. Для отрицательных N длина считается как (input.length() - abs(N)) */
void eraseTail( std::string & input, int n );

/**  \brief  Удалить последние N символов строки, вернуть исправленную копию
  Отсчёт с нуля. Для отрицательных N длина считается как (input.length() - abs(N))*/
std::string eraseTailCopy( const std::string & input, int n );



#else   // окончание без буста. Далее с бустом.


//!  \brief  Привести к верхнему регистру на месте
  void toUpper( std::string & v ) ;


//!  \brief Вернуть копию, приведённую к верхнему регистру
  std::string toUpperCopy( const std::string & v ) ;

//!  \brief Привести к нижнему регистру на месте
  void toLower( std::string & v ) ;



//!  \brief Вернуть копию, приведённую к нижнему регистру
  std::string toLowerCopy( const std::string & v ) ;

//!  \brief Обрезать пробелы и табуляции слева, на месте
  void trimLeft( std::string & v ) ;

//!  \brief Обрезать пробелы и табуляции слева, вернуть исправленную копию
  std::string trimLeftCopy( const std::string & v ) ;

//!  \brief Обрезать пробелы и табуляции справа, на месте
  void trimRight( std::string & v ) ;

//!  \brief Обрезать пробелы и табуляции справа, вернуть исправленную копию
  std::string trimRightCopy( const std::string & v ) ;

//!  \brief Обрезать пробелы и табуляции слева и справа, на месте
  void trim( std::string & v ) ;

//!  \brief Обрезать пробелы и табуляции слева и справа, вернуть исправленную копию
  std::string trimCopy( const std::string & v ) ;



//-------------------------------------------------------------------------
// Предикаты для использования в функциях поиска, или в обычных условиях
//-------------------------------------------------------------------------

//!  \brief Начинается ли строка text с фрагмента search?
  bool startsWith( const std::string & text, const std::string & search );



   //-----------------------

//! \brief Начинается ли строка text с фрагмента search? (без учёта регистра)
  bool iStartsWith( const std::string & text, const std::string & search ) ;

//!  \brief Завершается ли строка text фрагментом search?
  bool endsWith( const std::string & text, const std::string & search ) ;

//!  \brief Завершается ли строка text фрагментом search? (без учёта регистра)
  bool iEndsWith( const std::string & text, const std::string & search ) ;

//!  \brief Содержит ли строка text фрагмент search?
  bool contains( const std::string & text, const std::string & search ) ;

//!  \brief Содержит ли строка text фрагмент search? (без учёта регистра)
  bool iContains( const std::string & text, const std::string & search ) ;

 //---------------------

/**  \brief Равны ли строки друг другу
 (не имеет смысла в простом условии, но полезно, как предикат для поиска) */
inline bool equals( const std::string & a, const std::string & b )
{
	return a == b;
}
/** Равны ли строки друг другу без учёта регистра?
   (не имеет смысла в простом условии, но полезно, как предикат для поиска) */
  bool iEquals( const std::string & a, const std::string & b ) ;


//
//
//





//------------------------------------------------

/**  \brief  Разбить строку value на слова по символам указанным в split_charset, 
результат  сложить в destination  */
  void split( std::vector <std::string> & destination, const std::string & value, const std::string & split_charset );

  void split( std::list <std::string> & destination, const std::string & value, const std::string & split_charset );

  void split( std::set <std::string> & destination, const std::string & value, const std::string & split_charset );

		
		
//!  \brief Заменить первое вхождение search в строку input новым текстом replace
  void replaceFirst( std::string & input, const std::string & search, const std::string & replace );

//!  \brief Заменить первое вхождение search в строку input новым текстом replace, вернуть исправленную копию
  std::string replaceFirstCopy( const std::string & input, const std::string & search, const std::string & replace );

//!  \brief Заменить первое вхождение search в строку input новым текстом replace, без учёта регистра
  void iReplaceFirst( std::string & input, const std::string & search, const std::string & replace );

//!  \brief Заменить первое вхождение search в строку input новым текстом replace, без учёта регистра, вернуть исправленную копию
  std::string iReplaceFirstCopy( const std::string & input, const std::string & search, const std::string & replace );
		
//!  \brief Удалить первое вхождение search в строку input
  void eraseFirst( std::string & input, const std::string & search ) ;

//!  \brief Удалить первое вхождение search в строку input, вернуть исправленную копию
  std::string eraseFirstCopy( const std::string & input, const std::string & search ) ;

//! Удалить первое вхождение search в строку input, без учёта регистра
  void iEraseFirst( std::string & input, const std::string & search ) ;

/**  \brief Удалить первое вхождение search в строку input, без учёта регистра, 
  вернуть исправленную копию  */
  std::string iEraseFirstCopy( const std::string & input, const std::string & search ) ;

//!  \brief Заменить последнее вхождение search в строку input новым текстом replace
  void replaceLast( std::string & input, const std::string & search, const std::string & replace );

//!  \brief Заменить последнее вхождение search в строку input новым текстом replace, вернуть исправленную копию
  std::string replaceLastCopy( const std::string & input, const std::string & search, const std::string & replace );

//!  \brief Заменить последнее вхождение search в строку input новым текстом replace, без учёта регистра
  void iReplaceLast( std::string & input, const std::string & search, const std::string & replace );

//!  \brief Заменить последнее вхождение search в строку input новым текстом replace, без учёта регистра, вернуть исправленную копию
  std::string iReplaceLastCopy( const std::string & input, const std::string & search, const std::string & replace );

//!  \brief Удалить последнее вхождение search в строку input
  void eraseLast( std::string & input, const std::string & search ) ;

//!  \brief Удалить последнее вхождение search в строку input, вернуть исправленную копию
  std::string eraseLastCopy( const std::string & input, const std::string & search ) ;

//!  \brief Удалить последнее вхождение search в строку input, без учёта регистра
  void iEraseLast( std::string & input, const std::string & search ) ;


//!  \brief Удалить последнее вхождение search в строку input, без учёта регистра, вернуть исправленную копию
  std::string iEraseLastCopy( const std::string & input, const std::string & search ) ;


/**  \brief Заменить N-е вхождение search в строку input новым текстом replace
   Отсчёт с нуля. Отрицательные N считаются с конца строки */
  void replaceNth( std::string & input, const std::string & search, int n, const std::string & replace );

/**  \brief  Заменить N-e вхождение search в строку input новым текстом replace, 
      вернуть исправленную копию Отсчёт с нуля. 
      Отрицательные N считаются с конца строки  */
  std::string replaceNthCopy( const std::string & input, const std::string & search, int n, const std::string & replace );

/**  \brief Заменить N-e вхождение search в строку input новым текстом replace, 
      без учёта регистра.  Отсчёт с нуля. Отрицательные N считаются с конца строки   */
  void iReplaceNth( std::string & input, const std::string & search, int n, const std::string & replace );

/** \brief Заменить N-e вхождение search в строку input новым текстом replace, 
    без учёта регистра, вернуть исправленную копию  .
  Отсчёт с нуля. Отрицательные N считаются с конца строки */
  std::string iReplaceNthCopy( const std::string & input, const std::string & search, int n, const std::string & replace );

/** \brief Удалить N-e вхождение search в строку input
    Отсчёт с нуля. Отрицательные N считаются с конца строки  */
  void eraseNth( std::string & input, const std::string & search, int n ) ;

/** \brief Удалить N-e вхождение search в строку input, вернуть исправленную копию
    Отсчёт с нуля. Отрицательные N считаются с конца строки  */
  std::string eraseNthCopy( const  std::string & input, const std::string & search, int n );

/** \brief  Удалить N-e вхождение search в строку input, без учёта регистра
   Отсчёт с нуля. Отрицательные N считаются с конца строки  */
  void iEraseNth( std::string & input, const std::string & search, int n ) ;

/** \brief Удалить N-e вхождение search в строку input, без учёта регистра, вернуть исправленную копию
   Отсчёт с нуля. Отрицательные N считаются с конца строки  */
 std::string iEraseNthCopy( const std::string & input, const std::string & search, int n );

//! \brief Заменить каждое вхождение search в строку input новым текстом replace
 void replaceAll( std::string & input, const std::string & search, const std::string & replace );

//! \brief Заменить каждое вхождение search в строку input новым текстом replace, вернуть исправленную копию
 std::string replaceAllCopy( const std::string & input, const std::string & search, const std::string & replace );

//! \brief Заменить каждое вхождение search в строку input новым текстом replace, без учёта регистра
 void iReplaceAll( std::string & input, const std::string & search, const std::string & replace );

//! \brief Заменить каждое вхождение search в строку input новым текстом replace, без учёта регистра, вернуть исправленную копию
 std::string iReplaceAllCopy( const std::string & input, const std::string & search, const std::string & replace );

//! \brief Удалить каждое вхождение search в строку input
void eraseAll( std::string & input, const std::string & search ) ;

//! \brief Удалить каждое вхождение search в строку input, вернуть исправленную копию
 std::string eraseAllCopy( const std::string & input, const std::string & search );

//! \brief Удалить каждое вхождение search в строку input, без учёта регистра
 void iEraseAll( std::string & input, const std::string & search ) ;

//! \brief Удалить каждое вхождение search в строку input, без учёта регистра, вернуть исправленную копию
 std::string iEraseAllCopy( const std::string & input, const std::string & search );

/** \brief Заменить первые N символов строки input новым текстом replace
  Отсчёт с нуля. Для отрицательных N длина считается как (input.length() - abs(N)) */
 void replaceHead( std::string & input, int n, const std::string & replace ) ;

/** \brief  Заменить первые N символов строки input новым текстом replace, 
   вернуть исправленную копию .
   Отсчёт с нуля. Для отрицательных N длина считается как (input.length() - abs(N))  */
 std::string replaceHeadCopy( const std::string & input, int n, const std::string & replace );

/** \brief Заменить последние N символов строки input новым текстом replace
   Отсчёт с нуля. Для отрицательных N длина считается как (input.length() - abs(N)) */
 void replaceTail( std::string & input, int n, const std::string & replace ) ;

/** \brief Заменить последние N символов строки input новым текстом replace, 
   вернуть исправленную копию/ Отсчёт с нуля. 
   Для отрицательных N длина считается как (input.length() - abs(N))  */
 std::string replaceTailCopy( const std::string & input, int n, const std::string & replace );
		
/** \brief  Удалить первые N символов строки
   Отсчёт с нуля. Для отрицательных N длина считается как (input.length() - abs(N)) */
 void eraseHead( std::string & input, int n  ) ;

/** \brief Удалить первые N символов строки, вернуть исправленную копию
    Отсчёт с нуля. Для отрицательных N длина считается как (input.length() - abs(N)) */
 std::string eraseHeadCopy( const std::string & input, int n ) ;

/** Удалить последние N символов строки
   Отсчёт с нуля. Для отрицательных N длина считается как (input.length() - abs(N)) */
 void eraseTail( std::string & input, int n ) ;

/** \brief  Удалить последние N символов строки, вернуть исправленную копию
  Отсчёт с нуля. Для отрицательных N длина считается как (input.length() - abs(N)) */
 std::string eraseTailCopy( const std::string & input, int n ) ;

//-------------------------------------





#endif // KSSTR_ALLOW_BOOST_LIBRARY

 
   


static const char CSTR_ZERO []     = "0";
static const char CSTR_ONE  []     = "1";
static const char CSTR_TWO  []     = "2";




#ifdef KSSTR_ALLOW_BOOST_LIBRARY

template <typename T>
/** \brief Каст из строкового представления в другое */
bool strTo(  T& outVal,  const std::string& s)
{
	if( !s.length() ) return false;
	try { outVal = boost::lexical_cast<T>(s); }
	catch( boost::bad_lexical_cast &) {  return false; 	}	return true;
}


template<typename T>
/** \brief Каст из строкового вектора vSrc в тип T и положить результат кастования в vOut
Если при кастокании ошибка, то выполняется выход с возвратом false. Если каст всех значений
успешен вернёт true  */
bool strVectorTo(  std::vector<T>& vOut,  const std::vector<std::string>& vSrc)
{

	for(size_t c=0; c<vSrc.size(); c++)
	{
		T val;

		try
		{
			const std::string& src = vSrc[c];
			val  = boost::lexical_cast<T>( src );

		}
		catch( boost::bad_lexical_cast &)
		{
			return false;
		}

		vOut.push_back(val);

	} // for


	return true;
}

#endif // #ifdef KSSTR_ALLOW_BOOST_LIBRARY


//-------------------------------------------------------------------------
//    ks string functions   author: ksacvet777
//-------------------------------------------------------------------------

//! \brief УДалить все пустые строки из списка
void removeEmptyLines(std::vector<std::string>& lines);


/** \brief Заполнение вектора по строке делёной символом конца строки  '\n' */
void splitLines(  std::vector<std::string>& vOut, const std::string& s) ;

/** \brief сделать все символы в верхнем регистре. Строка должна завершаться нулём */
void cstrToUpper(char* buf) ;

/** \brief сделать все символы в нижнем регистре. Строка должна завершаться нулём */
void cstrToLower(char* buf) ;

/** \brief  Выполняет перевод буквеных символов в верхний(если bUpReg=true) или нижний(если bUpReg=false)
строки в NULL-терминированом буфере buff. <BR> Русские буквы переводятся в соответствии  с кодировкой cr1251
\param buff - [in] Исходный буфер подлежащий конвертации
\param bUpReg - [in]  Установить true если требуется перевод в верхний регистр или false для нижнего   */
void changeCase1251(char* buff, bool bUpReg);

/** \brief    Поиск индексов вхождения символа chToBeSearch в строке src
              с позиции  nStartIndex */
bool searchCharPos(  std::vector<int>& vPosOut, const std::string& src,
				   const char chToBeSearch, const int nStartIndex);


/** \brief Печать информации о строке на консоль. */
void printStrInfo(const std::string& s);
 
void replaceChar(std::string& s, const char chSymb, const char chNewSymb);

// void StrUt_BoostEraseAll(std::string& s, const std::string& s_erased);

bool loadStrFromFileA (  std::string& s,  const char* fname);
bool saveStrToFileA   (const  std::string& s,  const char* fname);

bool loadStrFromFileW (  std::string& s,  const wchar_t* fname);
bool saveStrToFileW   (const std::string& s,   const wchar_t* fname);



void BinaryDataToCppText(std::string& dest, const void* data, const size_t datalen);
void BinaryDataToSingleStrLine(std::string& dest, const void* data, const size_t datalen);



 
//#pragma message ("KS777 ПОПРАВИТЬ"  __FILE__)
//# 
/** \brief Сравнение буферов без учёта регистра   НЕ ПРОВЕРЯЛАСЬ !!! */
bool iCompareCstr(const char* src1, const char* src2, unsigned int nMax );

//! \brief Удалить все пустые строки из вектора
void removeEmptyLines(std::vector<std::string>& lines);


/** \brief  удалить из текста  все C++ комментарии. <br> 
	Если  chRepl != 0, то закомментированый текст будет заменён этим символом	 <br>
	(табы, пробелы и переносы строк не меняются)  */
void preprocessCppComments(  std::string& sDest, const std::string& sSrc,  const  char chRepl=0 );

/** \brief  удалить из текста  все C++ комментарии. Подробнее смотреть в одноимённой функции выше  */
void preprocessCppComments(  std::string& s,  const  char chRepl=0);



/** \brief Поиск индекса вхождения   символа. Минус один если не найден */
int findChar(const std::string& s, const char symb, const int nStartPos);

/** \brief Поиск подстроки между символами <br>
	nPosition - с какой позиции и в нём же 
	и результат индекса (позиция завершающего символа)  */
bool findSubstringBetween( 
						    std::string& sResult, const std::string& s,
						  const char chBegin,  
						  const char chEnd,
						    int& nPosition );

/** \brief Разрезать строку по указаному символу chDiv <br>
    bClearResVecBefore - очистить или нет результирующий вектор vResult перед операцией   */
void ksSplit(  std::vector<std::string>& vResult, const std::string& src,
			 const char chDiv,    bool bClearResVecBefore=true );


 
/** \brief Разрезать строку по токенам sTokens */
void splitTokens(   std::vector<std::string>& vResult,
				 const std::string& src, const std::string& sTokens );
 

/** \brief Разрезать строку по кол-ву указаному в pOffsets и  nOffsLen */
void sliceByOffsets(  std::vector<std::string>& vResult, const std::string& src,
					const unsigned int* pOffsets, const int nOffsLen) ;

/** \brief Разрезать строку src между индексами nStartPos && nStopPos
по токену  chToken   */
bool sliceBetweenIndices(  std::vector<std::string>& vOut,
						 const std::string& src,
						 const char  chToken,
						 const int nStartPos, const int nStopPos);


/** \brief Проверка на соответствие символа chr любому из szAny  */
bool isAnyOf(const char chr, const std::string& sAny) ;

/** \brief Выполнить поиск в строке src любого символа содержащегося  в sAny
с позиции posit . Если найден то вернёт true и в posit индекс вхождения  */
bool findAnyOf(const std::string& src,   int& posit, const std::string& sAny ) ;

/** \brief Выполнить поиск в строке src с позиции posit поиск
первого символа в диапазоне chBegin ... chEnd  (включительно) .
Если найден то вернёт true и в posit индекс вхождения */
bool findAnyOfBetween(const std::string& src,   int& posit, const char chBegin, const char chEnd);



/** \brief  Замена любого символа sAny   в строке src
на новый символ chNewSymb или удаление если chNewSymb == ноль. Результат в sOut  */
void replaceAnyChar(  std::string& sOut, const std::string &src, const std::string& sAny, const char chNewSymb);
void replaceAnyChar(  std::string &s, const std::string& sAny, const char chNewSymb) ;




/** \brief Проверка строчки на открывающий xml/html таг    */
bool check_OpenXmlTag(  std::string& sOutTag, const std::string& src);

/** \brief Проверка строчки на открывающий xml/html таг по индексу     */
bool check_OpenXmlTag_pos(  std::string& sOutTag, 
						  const std::string& src,
						    int& posit);

/** \brief Проверка строчки на закрывающий xml/html таг     */
bool check_CloseXmlTag(  std::string& sOutTag,	const std::string& src);

/** \brief Проверка строчки на закрывающий xml/html таг  по индексу    */
bool check_CloseXmlTag_pos(  std::string& sOutTag,
						   const std::string& src,
						     int& posit);




/** \brief Удаление символов начиная с "//" (с++ однострочный комментарий) */
void skipCppOnelineComment(  std::string& dest,	const std::string& src );

/** \brief Удаление символов начиная с "//" (с++ однострочный комментарий) */
void skipCppOnelineComment(  std::string& s);


void intArrayToStr(  std::string& sOut,
				   const int* pArray,  
				   const int nArrayLen,
				   const char* szBegin, 
				   const char* szEnd,
				   const char* szSeparator );


void intArrayToStr(  std::string& sOut,
				   const std::vector<int>& vArray,
				   const char* szBegin, 
				   const char* szEnd,
				   const char* szSeparator );


bool intArrayFromStr(
					   int* pBufOut, 
					 const int nBufLen,
					 const std::string& src, 
					 const char chBegin, 
					 const char chEnd,
					 const char chSeparator, 
					   int* pOutNumReaded = NULL  );


bool intArrayFromStr(
					   std::vector<int>& vOut, 
					 const std::string& src,
					 const char chBegin, 
					 const char chEnd, 
					 const char chSeparator );


/** \brief  найти следующий символ не равный символам sSkipAnySymbols
в строке src со стартовой позиции nStartPosit. Если найден вернёт true
и в nOutFoundPosit позиция найденого символа */
bool findNextSkipAny(  int& nOutFoundPosit, const std::string& src,
					 const int nStartPosit,
					 const std::string& sSkipAnySymbols );


/** \brief Удаление всех символов sAny из строки src с начала и с конца ДО ТОГО как
встретится символ не входящий в sAny. Результат в sOut  .Если других символов
помимо sAny в строке нет вернёт false. */
bool removeAnyFromBeginAndEnd(  std::string& sOut, const std::string& src, const std::string& sAny);

bool removeAnyFromBeginAndEnd(   std::string& s , const std::string& sAny) ;

/** \brief Аналог StrUt_RemoveAnyFromBeginAndEnd для вектора строк */
void removeAnyFromBeginAndEnd_Vec(  std::vector<std::string>& v,
								  const std::string& sAny);


/** \brief Построение текстового массива в строку sOut*/
void strArrayToStr(  std::string& sOut, ///< результат.
				   const std::vector<std::string> vecStr, ///< строки массива.
				   const char chBegin,  ///< начальный символ или ноль если не нужен.
				   const char chEnd,    ///< конечный символ или ноль если не нужен.
				   const char chSeparator, ///< разделитель пунктов массива.
				   bool bAddSpace   ///< добавить или нет пробел.
				   );


/** \brief  Обратная StrUt_WriteStringArrayToStr. Чтение строкового массива из src */
bool strArrayFromStr(   std::vector<std::string>& vOut,///<
					 const std::string& src,///<
					 const char chBegin, ///< токен начальный символ
					 const char chEnd, ///< токен конечный символ
					 const char chSeparator, ///< токен разделитель
					 const std::string& sRemoveBeginAndEndAny ///< для удалени начальных и конечных символов или пустая строка если нет
					 );


/** \brief Разрезать строку src в вектор vOut по индексам в vIndexes.
	В vIndexes должны быть корректные индексы (каждый должен  быть больше 
	предидущего и меньше следующего. 
	Каждый не должен превышать длину src ) */
bool sliceStrByIndices(std::vector<std::string>& vOut,  
					   const std::string& src, 
					   const std::vector<unsigned int>& vIndexes );


/** \brief Удалить из vInp все пустые строки, а непустые поместить в vOut */
void copyStringsSkipEmpty(std::vector<std::string>& vOut, std::vector<std::string>& vInp);


/** \brief Корректировак строки (добавление слеша (\) перед кавычкой ) */
//bool StrUt_CorrectStrBySpecSymbols_Add(_out std::string& sOut, _in std::string& src);





//---------------------------------------------------------------------
//                     INLINE    FUNCTIONS
//---------------------------------------------------------------------


/** \brief Проверка является ли символ цифровым */
inline bool isDigit(char symb) 
{
	return ( (symb>='0') && (symb<='9') );
}

/** \brief Проверка является ли символ англоязычным символом в ВЕРХНЕМ регистре. */
inline bool isLatinLetterUpper(char symb) 
{
	if (  (symb>='A') && (symb<='Z') ) return true;
	return false;
}

/** \brief Проверка является ли символ англоязычным символом в НИЖНЕМ регистре. */
inline bool isLatinLetterLower(char symb) 
{
	if (  (symb>='a') && (symb<='z') ) return true;
	return false;
}

/** \brief Проверка является ли символ англоязычным символом */
inline bool isLatinLetter(char symb) 
{
	return ( isLatinLetterUpper(symb) || isLatinLetterLower(symb) );
}

/** \brief Является ли символ математическим */
inline bool isMathOperator(char symb) 
{
	return ( (symb == '+') || (symb == '-') || (symb == '*') || (symb == '/')  );
}

/** \brief Присоединяет символ к строке. */
inline void appendChar(char* buf, const char s) 
{
	int iblen = (int)strlen(buf);
	*(buf + iblen) = s;
}

/** \brief Поиск символа новой строки . <br>
	\param
	src - указывает на первый символ в буфере.  
	pos - текущая позиция. */
bool findNextLinePos(const char* src, int& pos) ;


//! \brief Структура для поиска индексов (позиций) вхождения символа в строку. Для функции searchChars.
struct CharsPos_t {

	char charToBeSearsh; ///< символ , который требуется найти

	CharsPos_t(const char chrs): charToBeSearsh(chrs) {}
	CharsPos_t(const CharsPos_t& chs) : charToBeSearsh(chs.charToBeSearsh), vecFoundIndexes(chs.vecFoundIndexes) {}

	std::vector<int> vecFoundIndexes; ///< вектор индексов вхождения символа chToBeSearsh
};

//! \brief поиск в строке src с позиции nStartIndex символов в векторе vchpos  
bool searchChars( std::vector<CharsPos_t>& vchpos, 
				  const char* src,
				  //const std::string& src, 
				  int nStartIndex
				  );

		
//! \brief Поиск издекса подстроки substr в строке str.  Возвращает индекс вхождения или  -1 если не найдено
size_t cstrSearch_A(const char* src, const char* substr);

//! \brief Поиск издекса подстроки substr в строке str.  Возвращает индекс вхождения или  -1 если не найдено
size_t cstrSearch_W(const wchar_t* src, const wchar_t* substr);				  
			
/** \brief Разрезать строку. Символы до position будут в буфере bufBefore, 
а те что после (включительно) будут после.
 Например при параметрах "wwwoooo", 3 в bufBefore будет www, а в bufAfter будет oooo  */
bool cstrSlicePosition_A(char* bufBefore, char* bufAfter, const char* src, const size_t position);

/** \brief Разрезать строку. Символы до position будут в буфере bufBefore, 
а те что после (включительно) будут после.
Например при параметрах "wwwoooo", 3 в bufBefore будет www, а в bufAfter будет oooo  */
bool cstrSlicePosition_W(wchar_t* bufBefore, wchar_t* bufAfter, const wchar_t* src, const size_t position);			
				  
				  


/** \brief  make string:  "<tag>" */
inline std::string makeOpenXmlTag
(const std::string& sTag) {
	std::string  res  = "<";
	res += sTag;
	res += ">";
	return res;
}

/** \brief  make string:  "</tag>" */
inline std::string makeCloseXmlTag(const std::string& sTag) 
{
	std::string  res  = "</";
	res += sTag;
	res += ">";
	return res;
}

inline bool checkSymbolMayBeOpen(const char symb) 
{
	if( symb == '(' ) return true;
	if( symb == '{' ) return true;
	if( symb == '[' ) return true;
	if( symb == '<' ) return true;

	return false;
}

inline bool checkSymbolMayBeClose(  char symb) 
{
	if( symb == ')' ) return true;
	if( symb == '}' ) return true;
	if( symb == ']' ) return true;
	if( symb == '>' ) return true;

	return false;
}

inline bool checkSymbMayBeSeparator(  char symb) 
{
	if( symb == ',' ) return true;
	if( symb == ';' ) return true;

	return false;
}


//-----------------------------------------------------


void saveWstringToFileW(const std::wstring& filename, 
						const std::wstring& value) throw(std::runtime_error);

void loadWstringFromFileW(const std::wstring& filename, 
						  std::wstring& dest) throw (std::runtime_error);



std::wstring convertAstrToWstrDirect (const std::string  src);
std::string  convertWstrToAstrDirect (const std::wstring src);


//---------------------------------------------------------------------
//         Format    functions
//---------------------------------------------------------------------


/** \brief Преобразование bool в строку в буфер pDest размером ndestlen */
bool boolToCstr( char* pDest, int ndestlen, bool  value );
std::string boolToStr( bool  value );

/** \brief Преобразование value в строку в верхнем регистре 
в буфер pDest размером ndestlen */
bool boolToUppercaseCstr( char* pDest, int ndestlen, bool value );
std::string boolToUppercaseStr( bool value );

/** \brief Преобразование float в строку в буфер pDest размером ndestlen */
bool floatToCstr(char* pDest, int ndestlen, float value);
std::string  floatToStr(float value);

bool floatFromCstr(    float* out_val,  const char* s ) ;
bool floatFromCstr(    float& out_val,  const char* s ) ;

/** \brief Преобразование  знакового целого в строку . Если bAsCppHex true,  тогда конвертирует в HEX в стиль c++  */
bool intToCstr(char* pDest, int ndestlen,  int value, bool bAsCppHex);
/** \brief Преобразование  беззнакового целого в строку   Если bAsCppHex true,  тогда конвертирует в HEX в стиль c++  */
bool uintToCstr(char* pDest, int ndestlen, unsigned int value, bool bAsCppHex);

std::string intToStr  ( int value, bool bAsCppHex);
std::string uintToStr ( unsigned int value, bool bAsCppHex);


/** \brief Преобразование  знакового целого из строки. 

Если неверное значение или исключение, то вернёт false. Можно передавать число d HEX-c++. Например 0x5faf43   */
bool intFromCstr(  int* out_val, const char* s) ;
/** \brief Преобразование  знакового целого из строки. Если неверное значение или исключение, то вернёт false.  
Можно передавать число d HEX-c++. Например 0x5faf43  */
bool intFromCstr(  int& out_val, const char* s) ;

/** \brief  Аналог intFromCstr  для  unsigned int    */
bool uintFromCstr(  unsigned int* out_val, const char* s) ;
bool uintFromCstr(  unsigned int& out_val, const char* s) ;


/** \brief Преобразование  целого в строку  в шестнадцатеричном виде   */
bool intToHex(char* pDest, int ndestlen, int value) ;
/** \brief Преобразование  целого в строку  в шестнадцатеричном виде с префиксом "0x" */
bool intToCppHex(char* pDest, int ndestlen, int value) ; 

/** \brief  Перевод указателя в виде hex-строки  в буфер buff  с символами в верхнем регистре.  <BR>
Буфер должен быть длиной не менее 11 . Пример результата = 0xA23A98FC  */
bool pointerToCstr(char* pDest, int ndestlen, const void* p) ;

/** \brief Получение побитовой строки из байта . */
bool  byteToCStrAsBin(char* pDest, int ndestlen, unsigned char value);

/** \brief Преобразование unsigned int в двоичное представление. */
bool uintToBinCstr(char* pDest, int ndestlen, unsigned int value);
/** \brief Преобразование  int в двоичное представление. */
bool intToBinCstr(char* pDest, int ndestlen, unsigned int value);
/** \brief Преобразование unsigned int в двоичное представление. */
std::string uintToBinStr( unsigned int value);
/** \brief Преобразование int в двоичное представление. */
std::string intToBinStr( unsigned int value);


/** \brief Преобразование в uint из строки содержащей цифру в двоичном виде. */
unsigned int uintFromBinCstr(const char* _s, int nlen= -1)  throw(std::runtime_error&);

/** \brief побитовая печать на консоль двойного слова unsigned int */
void printUint32AsBin(  unsigned int value) ;

/** \brief печать  байта  в двоичном представлении на консоль . */
void printByteAsBin(unsigned char value) ;


#if defined (_WIN32)
/** \brief  Хэндл окна в строку */
unsigned int hwndAsUint(const HWND hwnd) ;
#endif


//---------------------------------------------------------------------

 


	class Keys;

	class Key {
		friend 	Keys;

	protected:
		std::string m_key;
		std::string m_value;
 

	public:

		static bool checkKeyValidName(const std::string& str) ;
		static bool checkValueValidName(const std::string& str) ;


		Key(const std::string& _key, const std::string& _value) throw ( std::runtime_error);
		Key(const std::string& key_and_value) throw ( std::runtime_error);
		~Key() {}	

		const std::string& key() const
		{
			return m_key;
		}

		const std::string& value() const
		{
			return m_value;
		}


	};



	class Keys : public std::vector<Key> {
	public:

		Keys() {  }

		size_t Add(const std::string& _key, const std::string& _value) throw(std::runtime_error);

		size_t searchKeyIndex(const std::string& keyName) ;

		bool checkKeyExists(const std::string& keyName) const ;

		void writeToText(std::string& text) const ;
		void readFromText(const std::string& str) throw(std::runtime_error);

		void writeToFile(const std::wstring& filename) throw(std::runtime_error);
		void readFromFile(const std::wstring& filename) throw(std::runtime_error);

		const std::string& getValue(const std::string& keyName) const throw(std::runtime_error);

		friend std::ostream& operator << (std::ostream& stream, const Keys& a)
		{
			for(size_t c=0; c<a.size(); c++)
			{
				stream << a.at(c).key() << "=" << a.at(c).value() << std::endl;
			}
			return stream;
		}


	};


	namespace test
	{
		void do_test_keys();
	}

 
//---------------------------------------------------------------------



class TextItemsHolder;

class text_item_s {

	friend TextItemsHolder;

private:
	std::string m_name;
	std::string m_text;

public:

	text_item_s(const std::string& name, const std::string& text) 
		: m_name(name), m_text(text)
	{

	}
};


class TextItemsHolder {
private:
	std::vector<text_item_s> m_items;

public:

	static bool IsLineName(std::string& name, const std::string& line) ;

	 TextItemsHolder() {}
	~TextItemsHolder() {}


	int NumElements() const 
	{
		return (int)m_items.size();
	}

	void WriteToText(std::string& dest) const ;

	bool SaveToFileW(const std::wstring& filename) const ;

	bool ReadFromText(const std::string& src) ;

	bool LoadFromFileW(const std::wstring& filename) ;

	text_item_s& Add(const std::string& name, const std::string& text) ;

	void Clear()
	{
		m_items.clear();
	}

	size_t SearchText(const std::string& text_name) const ;

	void GetTextAt(std::string& name, std::string& text, const size_t index) const ;


};





//---------------------------------------------------------------------
 
} 
// namespace ksstr

 



#pragma warning(pop)

// end file